<?php
/*####
#
#	Name: myForum
#	Version: 0.4
#	Author: Rick (rickdrummer@mail.ru)
#	Date: Mar 1, 2010
# Update: Apr 28, 2010
#
# Latest Version: http://rick.ru/modx/myforum/
# myForum Demo Site: http://epica-band.ru/forum/
#
####*/

include('myforum_db.class.inc.php');

class myForum {

	var $config = array();
	var $params = array();
	var $templates = array();
	var $db;

	function myForum() {
			
		global $modx;
		$path = $_SERVER['DOCUMENT_ROOT'];
		$this->db = new mf_DB();

	}
	
	function get($field) {
		return $this->parameters[$field];
	}
	
	function set($field, $value) {
		$this->parameters[$field] = $value;
	}
	
	function run(){
	
		global $modx;

		$this->config["path"] 	= $this->get("path");
		$this->config["mfInstallDir"] = $this->get("mfInstallDir");
		$this->config["css"] 		= !is_null($this->get("css")) ? $this->get("css") : '/'.$this->config["mfInstallDir"]."/css/styles.css";
		$this->config["lang"] 	= ($this->get("language"))? str_replace("/", "", $this->get("language")) : "eng";
		$this->config["userProfilesLink"] 	= $this->get("userProfilesLink");

		require('lang/'.$this->config["lang"].'.php');
		$this->appendPlaceholders($this->_lang, 'lang');
		
		// Templates
		$this->templates["front"] = !is_null($this->get("tplFront")) ? $this->get("tplFront") : $this->config["path"]."/templates/chunk.front.inc.html";
		$this->templates["topicsList"] = !is_null($this->get("tplTopicsList")) ? $this->get("tplTopicsList") : $this->config["path"]."/templates/chunk.topics_list.inc.html";
		$this->templates["topicModerate"] = !is_null($this->get("tplTopicModerate")) ? $this->get("tplTopicModerate") : $this->config["path"]."/templates/chunk.topic_moderate.inc.html";
		
		$this->templates["topicPage"] = !is_null($this->get("tplTopicPage")) ? $this->get("tplTopicPage") : $this->config["path"]."/templates/chunk.topic_page.inc.html";
		$this->templates["topicPost"] = !is_null($this->get("tplTopicPost")) ? $this->get("tplTopicPost") : $this->config["path"]."/templates/chunk.topic_post.inc.html";
		$this->templates["topicPostModerate"] = !is_null($this->get("tplTopicPostModerate")) ? $this->get("tplTopicPostModerate") : $this->config["path"]."/templates/chunk.post_moderation.inc.html";
		$this->templates["newTopicForm"] = !is_null($this->get("tplTopicForm")) ? $this->get("tplTopicForm") : $this->config["path"]."/templates/chunk.topic_form.inc.html";
		$this->templates["postEditForm"] = !is_null($this->get("tplPostEditForm")) ? $this->get("tplPostEditForm") : $this->config["path"]."/templates/chunk.post_edit_form.inc.html";
		$this->templates["pager"] = !is_null($this->get("tplPager")) ? $this->get("tplPager") : $this->config["path"]."/templates/chunk.pager.inc.html";
		$this->templates["pagerLink"] = !is_null($this->get("tplPagerLink")) ? $this->get("tplPagerLink") : $this->config["path"]."/templates/chunk.pager_link.inc.html";
		
		$this->params['forum_url'] = $this->get('mfUrl');
		$this->params['topicId'] = ($_GET['topicId']) ? intval($_GET['topicId']) : intval($_POST['topicId']);
		$this->params['loggedUserId'] = $modx->getLoginUserID();
		$lui = $this->userLoggedIn();
		$this->params['loggedUserType'] = $lui['usertype'];
		$this->params['userProfilesLink'] = $this->config["userProfilesLink"];
		$this->params['topicsPerPage'] = ($this->get('topicsPerPage'))? $this->get('topicsPerPage') : 10;
		$this->params['postsPerPage'] = ($this->get('postsPerPage'))? $this->get('postsPerPage') : 10;
		
		$this->db->firstRun($this->config["mfInstallDir"]);
		
		$this->appendPlaceholders($this->params);
		
		$src = '<link rel="stylesheet" type="text/css" href="'.$this->config["css"].'" />';
		$modx->regClientCSS($src);
		
		$a = ($_GET['a']) ? $_GET['a'] : $_POST['a'];
		
		switch($a){
			case 'newTopic':
				$o = $this->showNewTopicPage();
				break;
			case 'addNewTopic':
				$o = $this->addNewTopic();
				break;
			case 'showTopic':
				$o = $this->showTopic();
				break;
			case 'removeTopic':
				$o = $this->removeTopic();
				break;
			case 'addNewPost':
				$o = $this->addNewPost();
				break;
			case 'editPost':
				$o = $this->showPostEditForm();
				break;
			case 'updatePost':
				$o = $this->updatePost();
				break;
			case 'deletePost':
				$o = $this->deletePost();
				break;
			default:
				$o = $this->showFrontPage();
				break;
		}
		
		$this->getMessages();
		
		return $o;
		
	}
	
	/**
	 * Draw new topic html page
	 *
	 * @return
	 *   Rendered forum front page
	 */
	function showFrontPage() {
		global $modx;

		// process pager staff
		$currentPage = ($_GET['page']) ? intval($_GET['page']) : 0;
		$offset = ( $currentPage == 1 || $currentPage == 0 ) ? 0 : ($currentPage-1) * $this->params['postsPerPage'];
		$pager = $this->process_pager( null, $currentPage, $this->params['postsPerPage'] );
		$modx->setPlaceholder('forumPager', $pager);
		
		// get posts and place rendered html list into placeholder
		$result = $this->db->getTopicsList($offset, $this->params['postsPerPage']);
		$topics = '';
		while( $row = $modx->db->getRow( $result ) ) {
			$row['started_at_ru'] = $this->mf_date_format($row['started_at']);
			$row['last_post_at_ru'] = $this->mf_date_format($row['last_post_at']);
			$this->appendPlaceholders($row);
			$tMod = ( $this->params['loggedUserType'] == 'manager' ) ? $this->getRenderedChunk($this->templates["topicModerate"]) : '';
			$modx->setPlaceholder('topicModerationLinks', $tMod);
			$modx->setPlaceholder('token', $this->getToken());
			$topics .= $this->getRenderedChunk($this->templates["topicsList"]);
		}
		$modx->setPlaceholder('topicsList', $topics);
		$o = $this->getRenderedChunk($this->templates["front"]);
				
		return $o;

	}
	
	/**
	 * Draw new topic html page
	 *
	 * @return
	 *   Rendered forum front page
	 */
	function showTopic(){
	
		global $modx;

		// no topic id, no posts view
		if( !$this->params['topicId'] ) return $this->showFrontPage();
		
		// process pager staff
		$currentPage = ($_GET['page']) ? intval($_GET['page']) : 0;
		$offset = ( $currentPage == 1 || $currentPage == 0 ) ? 0 : ($currentPage-1) * $this->params['postsPerPage'];
		$pager = $this->process_pager( $this->params['topicId'], $currentPage, $this->params['postsPerPage'] );

		$modx->setPlaceholder('topicPager', $pager);
		
		// get posts and place rendered html list into placeholder
		$result = $this->db->getTopicPosts($this->params['topicId'], $offset, $this->params['postsPerPage']);
		$posts = '';
		
		while( $row = $modx->db->getRow( $result ) ) {
			$row['created_at_ru'] = $this->mf_date_format($row['created_at']);
			$row['content'] = str_replace("\n","<br />", $row['content']);
			$this->appendPlaceholders($row);
			$pMod = ( $row['author_id'] == $this->params['loggedUserId'] || $this->params['loggedUserType'] == 'manager' ) ? $this->getRenderedChunk($this->templates["topicPostModerate"]) : '';
			$modx->setPlaceholder('topicPostModeration', $pMod);
			$posts .= $this->getRenderedChunk($this->templates["topicPost"]);
		}
		$modx->setPlaceholder('topicPost', $posts);
		
		$modx->setPlaceholder('token', $this->getToken());
		
		// render topic page with posts
		$o = $this->getRenderedChunk($this->templates["topicPage"]);
		
		if ($this->params['loggedUserType'] != 'manager'){
			$this->db->incTopicViews($this->params['topicId']);
		}
		
		return $o;
	
	}
	
	/**
	 * Draw new topic html page
	 *
	 * @param $vars
	 *   Array of placeholders
	 * @return
	 *   Rendered forum new topic page
	 */
	function showNewTopicPage( $vars = array() ) {
		global $modx;
		$this->appendPlaceholders($vars);
		$o = $this->getRenderedChunk($this->templates["newTopicForm"]);
		
		return $o;

	}
	
	/**
	 * Insert new topic row
	 *
	 */
	function addNewTopic(){
		global $modx;
		
		// get vars, clean them and pack into array
		$topicTitle = $this->safePostData($_POST['mf_topic_title']);
		$topicContent = $this->safePostData($_POST['mf_topic_content']);
		$authorId = $this->params['loggedUserId'];
		$varsArray = array('topic_title' => $topicTitle, 'topic_content' => $topicContent);
		// some fields empty - show form again
		if( !$topicTitle || !$topicContent || !$authorId ){
			$this->setMessage($this->_lang['complete_all_fields']);
			return $this->showNewTopicPage( $varsArray );
		}
	
		// insert topic
		$fields = array(
			'title'				=> $topicTitle,
			'started_at' 		=> time(),
			'last_post_at'		=> time(),
			'starter_user_id'	=> $authorId,
			'last_post_user_id' => $authorId,
		);
		
		$topicId = $modx->db->insert( $fields, $modx->getFullTableName( 'myforum_topics' ));

		// insert post
		$fields = array(
			'topic_id'			=> $topicId,
			'title'				=> $topicTitle,
			'content'			=> $topicContent,
			'author_id'			=> $authorId,
			'created_at' 		=> time()
		);
		
		$postId = $modx->db->insert( $fields, $modx->getFullTableName( 'myforum_posts' ));

		// jump to new topic or show form again		
		if( $topicId ){
			header("HTTP/1.1 301 Moved Permanently"); 
			header("Location: ".$this->get('mfUrl')."topic/".$topicId."/");
		} else {
			$this->showNewTopicPage( $varsArray );
		}


	}
	
	/**
	 * Remove topic
	 *
	 */
	function removeTopic(){
	
		// get vars, clean them and pack into array
		$topicId = intval($_GET['topicId']);
		$token = $_GET['token'];
		if(!$this->validateToken($token) || $this->params['loggedUserType'] != 'manager'){ return ""; }		

		$r = $this->db->removeTopic($topicId);
		
		header("HTTP/1.1 301 Moved Permanently"); 
		header("Location: ".$this->get('mfUrl'));
		
	}
	
	/**
	 * Insert new post row
	 *
	 */
	function addNewPost(){
	
		global $modx;
		
		// get vars, clean them and pack into array
		$postTitle = $this->safePostData($_POST['mf_post_title']);
		$postContent = $this->safePostData($_POST['mf_post_content']);
		$authorId = $this->params['loggedUserId'];
		$varsArray = array('post_title' => $topicTitle, 'post_content' => $topicContent);
		$topicId = $this->params['topicId'];
	
		// some fields empty - show form again
		if( !$topicId || !$postContent || !$authorId ){
			$this->setMessage($this->_lang['complete_all_fields']);
			return $this->showTopic( $varsArray );
		}
	
		// insert post
		$fields = array(
			'topic_id'		=> $topicId,
			'title'			=> $postTitle,
			'content'		=> $postContent,
			'author_id'		=> $authorId,
			'created_at'	=> time()
		);
		
		$this->db->addNewPost($fields);

		// jump to new topic or show form again		
		if( $topicId ){
			header("HTTP/1.1 301 Moved Permanently"); 
			header("Location: ".$this->get('mfUrl')."topic/".$topicId."/");
		} else {
			$this->showTopic( $varsArray );
		}
	
	}
	
	/**
	 * Show form edit page
	 *
	 */
	function showPostEditForm(){

		global $modx;
		$postId = intval($_GET['postId']);
		$topicId = intval($_GET['topicId']);
		$modx->setPlaceholder('token', $this->getToken());
		
		$result = $this->db->getPostData($postId);
		$this->appendPlaceholders($result, 'post');
		$o = $this->getRenderedChunk($this->templates["postEditForm"]);
		return $o;
	
	}
	
	function updatePost(){
		
		global $modx;

		// validate token
		if(!$this->validateToken($_POST['token'])){ return ""; }

		// get vars, clean them and pack into array
		$postId = intval($_POST['mf_post_postId']);
		$topicId = intval($_POST['mf_post_topicId']);
		$postTitle = $this->safePostData($_POST['mf_post_title']);
		$postContent = $this->safePostData($_POST['mf_post_content']);
		$authorId = $this->params['loggedUserId'];
		
		// validate user rights
		$result = $this->db->getPostData($postId);
		
		if( $this->params['loggedUserType'] != 'manager' && $result['author_id'] != $this->params['loggedUserId'] ) { return ""; }
		
		// some fields empty - show form again
		if( !$postId || !$postTitle || !$postContent ){
			$this->setMessage($this->_lang['complete_all_fields']);
			return $this->showTopic();
		}
		
		$r = $this->db->updatePostData($postId, $postTitle, $postContent);
		
		if( $r ){
			header("HTTP/1.1 301 Moved Permanently"); 
			header("Location: ".$this->get('mfUrl')."topic/".$topicId."/");
		}
	
	}
	
	/**
	 * Remove post and do the cleanings
	 *
	 */
	function deletePost(){
	
		// get vars, clean them and pack into array
		$postId = intval($_GET['postId']);
		$topicId = intval($_GET['topicId']);
		$token = $_GET['token'];
		if(!$this->validateToken($token)){ return ""; }

		// validate user rights
		$result = $this->db->getPostData($postId);
		if( $this->params['loggedUserType'] != 'manager' && $result['author_id'] != $this->params['loggedUserId'] ) { return ""; }
		
		$r = $this->db->removePost($postId);
		
		$this->setMessage($this->_lang['post_removed']);
		
		if( $r == 'front' ){
			header("HTTP/1.1 301 Moved Permanently"); 
			header("Location: ".$this->get('mfUrl'));
		}
		
		if( $r == 'topic' ){
			header("HTTP/1.1 301 Moved Permanently"); 
			header("Location: ".$this->get('mfUrl')."topic/".$topicId."/");
		}

	}

	
	/**
	 * Clear input string from tags and other crap
	 *
	 * @param $string
	 *   Dirty string
	 * @return
	 *   Clean string
	 */
	function safePostData( $string ){
	
		global $modx;
	
		$string = $modx->db->escape($string);
		$string = strip_tags($string);
		$string = htmlspecialchars($string);
	
		return $string;
	
	}
	
	/**
	 * Convert array of vars to modx placeholder (with prefix "mf_")
	 *
	 * @param $vars
	 *   Array of vars ('placeholder'=>'value')
	 */
	function appendPlaceholders($vars, $suffix = ''){
		global $modx;
		
		$suffix = ($suffix) ? 'mf_'.$suffix.'_': 'mf_';
		
		foreach($vars as $k=>$v){
			$modx->setPlaceholder($suffix.$k, $v);
		}
	
	}

	/**
	 * Get chunk name or template filename and return chunk (if exist) or template (if file exist)
	 *
	 * @param $tpl
	 *   String - chunk name or template filepath
	 * @return
	 *   Rendered html
	 */
	function getRenderedChunk($tpl){
		global $modx;
		$template = "";
		if ($modx->getChunk($tpl) != "") {
			$o = $modx->parseChunk($tpl, $modx->placeholders, '[+', '+]');
		} else if(is_file($tpl)) {
			$o = file_get_contents($tpl);
			foreach ($modx->placeholders as $key => $value) {
				$o= str_replace('[+' . $key . '+]', $value, $o);
			}
		} else {
			$o = $tpl;
		}
		
		return $o;
	}
	
	
	/**
	 * Process pager for topics or posts page
	 *
	 * @param $topicId
	 *   Int - if exist pager will count for topic page if not for front page
	 * @param $currentPage
	 *   Int - value for current page
	 * @param $postsPerPage
	 *   Int - param for per page items
	 * @return
	 *   Rendered pager template
	 */
	function process_pager( $topicId, $currentPage, $postsPerPage ){
	
		global $modx;
	
		$topicId 			= intval($topicId);
		$currentPage 	= intval($currentPage);
		$postsPerPage = intval($postsPerPage);
		
		$forumUrl = $this->params['forum_url'];
		
		$qCount = ($topicId)? $this->db->getPostsCount($topicId) : $this->db->getTopicsCount();
		$pages = ceil($qCount / $postsPerPage);
		
		$href = ( $topicId ) ? $forumUrl.'topic/'.$topicId.'/' : $forumUrl;
		
		$showPages = 7;

		if (!$currentPage) {
			$currentPage = 1;
		}
		
		$pageNavigatorArray = array();

		for($i=1;$i<=$pages;$i++){
		
			// last page
			if($i > $showPages+$currentPage){
				$pageNavigatorArray[] = array('pageNo' => '', 'href' => '', 'pageText' => ' ... ', 'pageStatus' => '2');
				$pageNavigatorArray[] = array('pageNo' => $pages, 'href' => $href.'page/'.$pages.'/', 'pageText' => $pages, pageStatus => '');
				break;
			}

			// first page
			if($i < $currentPage-$showPages){
				if(!$blank){
					$blank=1;
					$pageNavigatorArray[] = array('pageNo' => '1', 'href' => $href, 'pageText' => 1, 'pageStatus' => '');
					$pageNavigatorArray[] = array('pageNo' => '', 'href' => '', 'pageText' => ' ... ', 'pageStatus' => '2');
				}
				continue;
			}

			// other page
			if ($currentPage == $i) {
				$pageNavigatorArray[] = array('pageNo' => $i, 'href' => $href.'page/'.$i.'/', 'pageText' => $i, 'pageStatus' => '1');
			} else {
				$pageHref = ($i == 1) ? $href : $href.'page/'.$i.'/';
				$pageNavigatorArray[] = array('pageNo' => $i, 'href' => $pageHref, 'pageText' => $i, 'pageStatus' => '');
			}

		}
		
		$pager_links = '';
		
		if( count($pageNavigatorArray) > 1 ){
		
			foreach( $pageNavigatorArray as $k=>$v ){
				$this->appendPlaceholders($v, 'pager');
				$pager_links .= $this->getRenderedChunk($this->templates["pagerLink"]);
			}
			
			$modx->setPlaceholder('pagerLinkHtml', $pager_links);
			return $this->getRenderedChunk($this->templates["pager"]);
		
		} else {
		
			return '';
			
		}
	
	}
	
	/**
	 * Generate unique token value for safe web actions
	 *
	 * @param $extraString
	 *   Extra string for security
	 * @return
	 *   Unique token
	 */
	function getToken($extraString = ''){
		return md5(session_id().$extraString);
	}
	
	/**
	 * Validate given token
	 *
	 * @return
	 *   true || false
	 */
	function validateToken($token, $extraString = ''){
		return ($token == md5(session_id().$extraString));
	}
	
	/**
	 * Set message to global SESSION var
	 *
	 * @param $msg
	 *   String with message
	 * @return
	 *   if there is no params, return all messages
	 */
	function setMessage($msg = NULL){
	
	    if (!isset($_SESSION['msgs'])) {
			$_SESSION['msgs'] = array();
		}

		if( $msg ){
			$_SESSION['msgs'][] = $msg;
		}
	
	}
	
	/**
	 * Set message to global SESSION var
	 *
	 * @param $msg
	 *   String with message
	 * @return
	 *   if there is no params, return all messages
	 */
	function getMessages($msg = NULL){
	
		if( isset($_SESSION['msgs']) ){
			$msgs = $_SESSION['msgs'];
			unset($_SESSION['msgs']);
			$o = '';
			foreach($msgs as $k=>$v){
				$o .= '<p>'.$v.'</p>';
			}
			$this->appendPlaceholders(array('messages' => $o));
		}
	
	}
	
	/**
	* Returns date in '12 may 2010' format (for ru date)
	*
	* @param $ts
	*   	unix timestamp
	* @param $format
	*   	short
	*
	* @return
	*  '12 may 2010'
	*/
	function mf_date_format($ts, $format = ''){

	  $d = date('j-n-Y',$ts);
	  list($day, $month, $year) = explode("-", $d);

	  $t = date('H:i',$ts);

	  $m = array('', 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря');
	  if($format == 'short'){
			return ( $this->config["lang"] != 'rus_utf8' ) ? date('Y F j',$ts) : $day.' '.$m[$month].' '.$year;
	  } else {
			return ( $this->config["lang"] != 'rus_utf8' ) ? date('Y F j',$ts).' '.$t : $day.' '.$m[$month].' '.$year.' '.$t;
	  }

	}

	/**
	* Bypass of the MODx userLoggedIn, because native function can't return manager user data
	*
	* @return
	*  userData array, true or false
	*/
	function userLoggedIn() {
	
		global $modx;
		$webVal = isset($_SESSION['webValidated']);
		$mgrVal = isset($_SESSION['mgrValidated']);
		if ($modx->isFrontend()){ //on frontend
			if ($webVal){ //webuser is logged in
				$auth = true;
				$type = 'web';
				$prefix = 'web';
			} elseif ($mgrVal){ //manager is logged in
				$auth = true;
				$type = 'manager';
				$prefix = 'mgr';
			} else { //neither is logged in
				$auth = false;
			}
		} elseif ($modx->isBackend() && $mgrVal){ //inside manager and authenticated
			$auth = true;
			$type = 'manager';
			$prefix = 'mgr';
		} else { //if all else fails...
			$auth = false;
		}
		if ($auth){ //if some user logged in...
			$userdetails= array (
				'loggedIn' => true,
				'id' => $_SESSION[$prefix.'InternalKey'],
				'username' => $_SESSION[$prefix.'Shortname'],
				'usertype' => $type // added by Raymond
			);
			return $userdetails;
		}else{
			return false;
		}
	}
	
}
?>